/-imports ...
/-imports/acorn
/-imports/codemirror
/-imports/knockout
/-imports/tern ...
comment.js
def.js
doc_comment.js
infer.js
signal.js
tern.js
/-imports/typescript
/-imports/zip.js
/-layout
/-typings
TypeScriptService.ts
editor-std.ts
editor-x-css.ts
editor-x-html.ts
editor-x-js.ts
editor-x-ts.ts
editor.ts
files.ts
ko.ts
persistence.ts
shell.ts
teapo.html
teapo.js
teapo.ts
506
  function isStringAround(node, start, end) {
507
    return node.type == "Literal" && typeof node.value == "string" &&
508
      node.start == start - 1 && node.end <= end + 1;
509
  }
510
 
511
  function findCompletions(srv, query, file) {
512
    if (query.end == null) throw ternError("missing .query.end field");
513
    var wordStart = resolvePos(file, query.end), wordEnd = wordStart, text = file.text;
514
    while (wordStart && acorn.isIdentifierChar(text.charCodeAt(wordStart - 1))) --wordStart;
515
    if (query.expandWordForward !== false)
516
      while (wordEnd < text.length && acorn.isIdentifierChar(text.charCodeAt(wordEnd))) ++wordEnd;
517
    var word = text.slice(wordStart, wordEnd), completions = [];
518
    if (query.caseInsensitive) word = word.toLowerCase();
519
    var wrapAsObjs = query.types || query.depths || query.docs || query.urls || query.origins;
520
 
521
    function gather(prop, obj, depth) {
522
      // 'hasOwnProperty' and such are usually just noise, leave them
523
      // out when no prefix is provided.
524
      if (query.omitObjectPrototype !== false && obj == srv.cx.protos.Object && !word) return;
525
      if (query.filter !== false && word &&
526
          (query.caseInsensitive ? prop.toLowerCase() : prop).indexOf(word) != 0) return;
527
      for (var i = 0; i < completions.length; ++i) {
528
        var c = completions[i];
529
        if ((wrapAsObjs ? c.name : c) == prop) return;
530
      }
531
      var rec = wrapAsObjs ? {name: prop} : prop;
532
      completions.push(rec);
533
 
534
      if (query.types || query.docs || query.urls || query.origins) {
535
        var val = obj ? obj.props[prop] : infer.ANull;
536
        infer.resetGuessing();
537
        var type = val.getType();
538
        rec.guess = infer.didGuess();
539
        if (query.types)
540
          rec.type = infer.toString(type);
541
        if (query.docs)
542
          maybeSet(rec, "doc", val.doc || type && type.doc);
543
        if (query.urls)
544
          maybeSet(rec, "url", val.url || type && type.url);
545
        if (query.origins)
546
          maybeSet(rec, "origin", val.origin || type && type.origin);
547
      }
548
      if (query.depths) rec.depth = depth;
549
    }
550
 
551
    var memberExpr = infer.findExpressionAround(file.ast, null, wordStart, file.scope, "MemberExpression");
552
    if (memberExpr &&
553
        (memberExpr.node.computed ? isStringAround(memberExpr.node.property, wordStart, wordEnd)
554
                                  : memberExpr.node.object.end < wordStart)) {
555
      var prop = memberExpr.node.property;
556
      prop = prop.type == "Literal" ? prop.value.slice(1) : prop.name;
557
 
558
      memberExpr.node = memberExpr.node.object;
559
      var tp = infer.expressionType(memberExpr);
560
      if (tp) infer.forAllPropertiesOf(tp, gather);
561
 
562
      if (!completions.length && query.guess !== false && tp && tp.guessProperties) {
563
        tp.guessProperties(function(p, o, d) {if (p != prop && p != String.fromCharCode(0x2716)) gather(p, o, d);});
564
      }
565
      if (!completions.length && word.length >= 2 && query.guess !== false)
566
        for (var prop in srv.cx.props) gather(prop, srv.cx.props[prop][0], 0);
567
    } else {
568
      infer.forAllLocalsAt(file.ast, wordStart, file.scope, gather);
569
    }
570
 
571
    if (query.sort !== false) completions.sort(compareCompletions);
572
 
573
    return {start: outputPos(query, file, wordStart),
574
            end: outputPos(query, file, wordEnd),
575
            completions: completions};
576
  }
577
 
578
  function findProperties(srv, query) {